package hhs.scannerapp;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.opencv.android.JavaCameraView;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.os.Environment;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class PictureTakerViewTimer extends JavaCameraView 
{
	private static final String TAG = "PictureTakerViewTimer";
	private int pictNum = 0;
	private int numOfPicts = 24;
	//if picture is too long duration is too slow
	private int duration = 10000;
	private int interval;
	private Handler handler = new Handler();
	private Mat output, cropped, cropped2, cropped3, cropped4;
	private Rect rect,rect2,rect3,rect4;
	private Point tl,br;
	protected PictureTakerCropActivity context;
	private Point [] slicePoints,slicePoints2,slicePoints3,slicePoints4;
	private EdgeFinder edgeFinder;
	public ArrayList<Mat> pictureList = new ArrayList<Mat>();
	public boolean done = false;
	
	public PictureTakerViewTimer(Context context, AttributeSet attrs) 
	{
		super(context, attrs);
		this.context = (PictureTakerCropActivity) context; 
	} 

	// Create a File for saving the image 
	private File getOutputMediaFile()
	{
		boolean haveDir = true;
		File mediaStorageDir = new File(Environment.getExternalStorageDirectory().getPath(),"AppPictures");
		File mediaFile = null;

		if (!mediaStorageDir.exists())
		{
			if (!mediaStorageDir.mkdirs())
			{
				haveDir = false;
				return null;
			}
		}

		if(haveDir)
		{	
			mediaFile = new File(mediaStorageDir.getPath() + File.separator + "texture" + ".png");	
		}
		return mediaFile;	
	}

	public void takeTexturePicture(int duration) 
	{	
		System.gc();
		pictNum++;
				
		if(pictNum == 1)
		{
			if(context.shape.equals("box"))
			{
				numOfPicts = 4;
			}
			this.duration = duration;
			interval = this.duration/numOfPicts;
		}
		if(pictNum <= numOfPicts)
		{
			Log.i(TAG, "PictNum = " + pictNum + "   numOfPicts = " + numOfPicts);
			Runnable runnable = new Runnable()
			{
				public void run() 
				{
					mCamera.startPreview();	
					mCamera.takePicture(null, null, picture);
				}
			};
			handler.postDelayed(runnable, interval);	
			context.startView.setText("Picture " + pictNum);
		}
		else
		{		   		
			makePreviewInvisible();
			processPictures();	
		}
	}
	
	public void takeNoTexturePicture()
	{	
		if(context.shape.equals("cylinder"))
		{
			Log.e("Cylinder","No Texture Cylinder");
			context.startView.setText(R.string.no_text_cylinder);
		}
		else if(context.shape.equals("box"))
		{
			Log.e("Box","No Texture Box");
			context.startView.setText(R.string.no_text_box);
		}
		
		context.cameraButton.setVisibility(VISIBLE);
		context.cameraButton.setOnClickListener(new View.OnClickListener() 
		{
			@Override
			public void onClick(View v) 
			{
				mCamera.startPreview();	
				mCamera.takePicture(null, null, picture);
			}
		});
	}

	private PictureCallback picture = new PictureCallback() 
	{
		@Override
		public void onPictureTaken(byte[] data, Camera camera) 
		{	
			Log.e("picturecallback", context.shape);
			
			if(context.textureString.equals("texture"))
			{
				if(context.shape.equals("cylinder"))
				{
					Log.d("PictureCallback", Integer.toString(pictNum));
					Bitmap bmp = BitmapFactory.decodeByteArray(data , 0, data.length);
					Mat imageMat = new Mat(bmp.getHeight(),bmp.getWidth(),CvType.CV_8UC1);
					Utils.bitmapToMat(bmp, imageMat);
					bmp.recycle();
					pictureList.add(imageMat);	
				}
				else if(context.shape.equals("box"))
				{
					Log.d("PictureCallback", Integer.toString(pictNum));
					Bitmap bmp = BitmapFactory.decodeByteArray(data , 0, data.length);
					Mat imageMat = new Mat(bmp.getHeight(),bmp.getWidth(),CvType.CV_8UC1);
					Utils.bitmapToMat(bmp, imageMat);
					bmp.recycle();
					pictureList.add(imageMat);		
				}
				
				takeTexturePicture(duration);	
			}
			else if(context.textureString.equals("no texture"))
			{
				Bitmap tempBmp = null;
				
				if(context.shape.equals("cylinder"))
				{
					tempBmp = BitmapFactory.decodeByteArray(data , 0, data.length);
					Mat imageMat = new Mat(tempBmp.getHeight(),tempBmp.getWidth(),CvType.CV_8UC1);
					Utils.bitmapToMat(tempBmp, imageMat);
					context.cameraButton.setVisibility(GONE);
					context.startView.setText(R.string.rendering);
					File outFile = new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"AppPictures/temp0.png");
					tempBmp = Bitmap.createBitmap(imageMat.cols(),imageMat.rows(), Bitmap.Config.RGB_565);
					Utils.matToBitmap(imageMat, tempBmp);
					try 
					{
						FileOutputStream fos = new FileOutputStream(outFile);
						tempBmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
						fos.close();
					} 
					catch(IOException ignored){}
					finally
					{
						tempBmp.recycle();
						makePreviewInvisible();
					}
					startModelling();
				}
				else if(context.shape.equals("box"))
				{
					pictNum++;
					
					if(pictNum == 1)
					{
						tempBmp = BitmapFactory.decodeByteArray(data , 0, data.length);
						Mat imageMat = new Mat(tempBmp.getHeight(),tempBmp.getWidth(),CvType.CV_8UC1);
						Utils.bitmapToMat(tempBmp, imageMat);
						File outFile = new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"AppPictures/temp0.png");
						tempBmp = Bitmap.createBitmap(imageMat.cols(),imageMat.rows(), Bitmap.Config.RGB_565);
						Utils.matToBitmap(imageMat, tempBmp);
						try 
						{
							FileOutputStream fos = new FileOutputStream(outFile);
							tempBmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
							fos.close();
						} 
						catch(IOException ignored){}
						finally
						{
							tempBmp.recycle();   		
						}
						context.startView.setText(R.string.no_text_box2);
					}
					else if(pictNum == 2)
					{
						tempBmp = BitmapFactory.decodeByteArray(data , 0, data.length);
						File outFile = new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"AppPictures/temp1.png");
						tempBmp = Bitmap.createBitmap(tempBmp,0,0,tempBmp.getWidth(),tempBmp.getHeight());
						try 
						{
							FileOutputStream fos = new FileOutputStream(outFile);
							tempBmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
							fos.close();
						} 
						catch(IOException ignored){}
						finally
						{
							tempBmp.recycle();
							makePreviewInvisible();
						}
						context.cameraButton.setVisibility(GONE);
						context.startView.setText(R.string.rendering);
						startModelling();
					}	
				}
			}
		}
	};
	
	public void makePreviewInvisible()
	{
		this.setVisibility(GONE);	
		disableView();
		releaseCamera();
	}

	public void processPictures()
	{
		Log.e("processPictures", pictureList.size() + "");
		context.startView.setText("Finished Taking Pictures");  
		if(context.shape.equalsIgnoreCase("cylinder")){
			for(int i = 0; i < pictureList.size(); i++)
			{
				if(i == 0)
				{	
					File outFile = new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"AppPictures/temp0.png");
					Bitmap bmp = Bitmap.createBitmap(pictureList.get(0).width(), pictureList.get(0).height(),Bitmap.Config.RGB_565);
					Utils.matToBitmap(pictureList.get(0), bmp);
					Matrix matrix = new Matrix();
					matrix.preScale(1, -1);
					bmp = Bitmap.createBitmap(bmp,0,0,bmp.getWidth(),bmp.getHeight(), matrix, true);
					try 
					{
						FileOutputStream fos = new FileOutputStream(outFile);
						bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
						fos.close();
					} 
					catch(IOException ignored){}
					finally{
						bmp.recycle();
					}
	//				Log.e("processPictures", "i = 0");
	//				Log.e("PictureList", "Mat Size " + pictureList.get(0).rows() + "   " + pictureList.get(0).cols());
					Mat picture = pictureList.get(i).clone();
					edgeFinder = new EdgeFinder(picture, context.threshString);
					slicePoints = edgeFinder.getTexturePoints();
					rect = new Rect(slicePoints[0], slicePoints[1]);		
					cropped = new Mat(pictureList.get(i), rect);
					output = new Mat(cropped.rows(),cropped.cols()*pictureList.size(),CvType.CV_8UC4);
	
					//adds back to full picture
					tl = new Point(0,0);
					br = new Point(cropped.size().width,cropped.size().height);
					Mat first = new Mat(output, new Rect(tl,br));
					cropped.copyTo(first);
	//				Log.e("processPictures", output.rows() + "   " + output.cols());
				}
				else
				{
					cropped = new Mat(pictureList.get(i), rect);	
					tl = new Point(cropped.size().width *i, 0);
					br = new Point(cropped.size().width*(i+1), cropped.size().height);
					Mat otherMats = new Mat(output,new Rect(tl,br));
					cropped.copyTo(otherMats);	
				}
			}
	
			File pictureFile = getOutputMediaFile();
			if (pictureFile == null)
			{
				Log.d("PictureCallback", "Error creating media file");
			}
			else
			{	
				// Write the image in a file (in png format)
	
				Matrix mat = new Matrix();
				mat.postRotate(180);      
				Bitmap cropBitmap = Bitmap.createBitmap(output.cols(), output.rows(), Bitmap.Config.ARGB_8888);
				Utils.matToBitmap(output, cropBitmap);
				cropBitmap = Bitmap.createBitmap(cropBitmap, 0, 0, cropBitmap.getWidth(), cropBitmap.getHeight(), mat, true);
				FileOutputStream fos = null;
				try {
					fos = new FileOutputStream(pictureFile);
					cropBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
					fos.close();
				}
				catch (FileNotFoundException e1) {
					e1.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				cropBitmap.recycle(); 
			}
	
			startModelling();
		}
		
		else if(context.shape.equalsIgnoreCase("box"))
		{
			File outFile = new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"AppPictures/temp0.png");
			Bitmap bmp = Bitmap.createBitmap(pictureList.get(0).width(), pictureList.get(0).height(),Bitmap.Config.RGB_565);
			Utils.matToBitmap(pictureList.get(0).clone(), bmp);
			Matrix matrix = new Matrix();
			matrix.preScale(1, -1);
			bmp = Bitmap.createBitmap(bmp,0,0,bmp.getWidth(),bmp.getHeight(), matrix, true);
			try {
				FileOutputStream fos = new FileOutputStream(outFile);
				bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
				fos.close();
			} 
			catch(IOException ignored){}
			finally{
				bmp.recycle();
			}
			
			outFile = new File(Environment.getExternalStorageDirectory().getPath()+File.separator+"AppPictures/temp1.png");
			bmp = Bitmap.createBitmap(pictureList.get(1).width(), pictureList.get(1).height(),Bitmap.Config.RGB_565);
			Utils.matToBitmap(pictureList.get(1).clone(), bmp);
			matrix = new Matrix();
			matrix.preScale(1, -1);
			bmp = Bitmap.createBitmap(bmp,0,0,bmp.getWidth(),bmp.getHeight(), matrix, true);
			try {
				FileOutputStream fos = new FileOutputStream(outFile);
				bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
				fos.close();
			} 
			catch(IOException ignored){}
			finally{
				bmp.recycle();
			}
			
		
			
			
			Log.e("PictureList", "Mat Size " + pictureList.get(0).empty() + " " +pictureList.get(1).empty() + " " +pictureList.get(2).empty() + " " +pictureList.get(3).empty() );
			Mat picture = pictureList.get(3).clone();
			EdgeFinder edgeFinder1 = new EdgeFinder(picture, context.threshString);
			slicePoints = edgeFinder.getCorners();
			rect = new Rect(slicePoints[0], slicePoints[1]);
//			
			Mat picture2 = pictureList.get(2).clone();
//			EdgeFinder edgeFinder = new EdgeFinder(picture, context.threshString);
//			slicePoints2 = edgeFinder.getCorners();
//			rect2 = new Rect(slicePoints2[0], slicePoints2[1]);		
			cropped = new Mat(pictureList.get(0).clone(), rect);		
			cropped2 = new Mat(pictureList.get(1).clone(), rect);			
			cropped3 = new Mat(pictureList.get(2).clone(), rect);			
			cropped4 = new Mat(pictureList.get(3).clone(), rect);	
			
			output = new Mat(cropped2.rows(),(cropped.cols()+cropped2.cols()+cropped3.cols()+cropped4.cols()),CvType.CV_8UC4);
			tl = new Point(0, 0);
			br = new Point(cropped4.size().width, output.size().height);
			Mat otherMats = new Mat(output,new Rect(tl,br));
			cropped4.copyTo(otherMats);	
			tl = new Point(cropped4.size().width, 0);
			br = new Point(cropped4.size().width+ cropped3.size().width, output.size().height);
			otherMats = new Mat(output,new Rect(tl,br));
			cropped3.copyTo(otherMats);	
			tl = new Point(cropped4.size().width+ cropped3.size().width, 0);
			br = new Point(cropped4.size().width+ cropped3.size().width+cropped2.size().width, output.size().height);
			otherMats = new Mat(output,new Rect(tl,br));
			cropped2.copyTo(otherMats);	
			tl = new Point(cropped4.size().width+ cropped3.size().width+cropped2.size().width, 0);
			br = new Point(cropped4.size().width+ cropped3.size().width+cropped2.size().width+cropped.size().width, output.size().height);
			otherMats = new Mat(output,new Rect(tl,br));
			cropped.copyTo(otherMats);	
			
			Log.e("Pictures", cropped.size()+"   "+cropped2.size()+"   "+cropped3.size()+"   "+cropped4.size()+"   ");
			Log.e("Pictures", output.size() +"");
			
			File pictureFile = getOutputMediaFile();
			if (pictureFile == null)
			{
				Log.d("PictureCallback", "Error creating media file");
			}
			else
			{	
				// Write the image in a file (in png format)
	
				Matrix mat = new Matrix();
				mat.postRotate(180);      
				Bitmap cropBitmap = Bitmap.createBitmap(output.cols(), output.rows(), Bitmap.Config.ARGB_8888);
				Utils.matToBitmap(output, cropBitmap);
				cropBitmap = Bitmap.createBitmap(cropBitmap, 0, 0, cropBitmap.getWidth(), cropBitmap.getHeight(), mat, true);
				FileOutputStream fos = null;
				try {
					fos = new FileOutputStream(pictureFile);
					cropBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
					fos.close();
				}
				catch (FileNotFoundException e1) {
					e1.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				cropBitmap.recycle(); 
			}
			startModelling();
		}
	}

	private void startModelling() {
		Toast.makeText(getContext(), "Creating Model", Toast.LENGTH_SHORT).show();
		Intent run = new Intent(getContext(), ModelActivity.class);
		run.putExtra("modeltype", context.shape);
		run.putExtra("thresholdtype", context.threshString);
		run.putExtra("textureconfig", context.textureString);
		context.startActivity(run);		
	}

	public void releaseCam()
	{
		if (mCamera != null)
		{
			mCamera.release();        // release the camera for other applications
			mCamera = null;
		}
	}
}